#include "ThreadImpl_Win.h"

#include "WinExpection.h"
#include "tools/helpMacros.h"

#include SD_TL_PLATFORM_IMPL_INC( tools,HandleWraper )

#include <Windows.h>

using namespace sd::tools;
using namespace sd::tools::thread;
using namespace sd::tools::thread::impl;




ThreadImpl::ThreadImpl( int uid )
{
	handle_ = HHANDLE(OpenThread(THREAD_ALL_ACCESS,FALSE, uid));
	if(!handle_)
		throw win::WinImplException("Open thread error");
	CheckSuspendState();
}
ThreadImpl::ThreadImpl( const HHANDLE& handle ):handle_(handle){ 	CheckSuspendState(); }


void ThreadImpl::kill()
{
	TerminateThread(handle_.impl(),0);
}

void ThreadImpl::CheckSuspendState()
{
	if(GetCurrentThreadId() == GetThreadId(handle_.impl()))
	{
		suspend_=false;
		return;
	}
    DWORD dwSuspendCount = SuspendThread(handle_.impl());
    ResumeThread(handle_.impl());
	suspend_ = !!dwSuspendCount;
}


void ThreadImpl::suspend()
{
	SuspendThread(handle_.impl());
	suspend_ = true;
}
void ThreadImpl::resume()
{
	ResumeThread(handle_.impl());
	suspend_ = false;
}
void ThreadImpl::join()
{
	WaitForSingleObject( handle_.impl(), INFINITE);
}
bool ThreadImpl::timed_join(int msec)
{
	return WaitForSingleObject( handle_.impl(), msec)!=WAIT_TIMEOUT;
}

bool ThreadImpl::isSuspended()const
{
	return suspend_;
}


const void* ThreadImpl::getCurrentEIP()const
{
	if(!isSuspended() || isFinished())
		return NULL;

	CONTEXT context; 
	context.ContextFlags = (CONTEXT_CONTROL);

	if(!GetThreadContext(handle_.impl(), &context))
		throw win::WinImplException("Get thread context");

	return (const void*)context.Eip;
}


bool ThreadImpl::isFinished()const
{
	DWORD code;
	if(!GetExitCodeThread(handle_.impl(), &code))
		throw win::WinImplException("GetExitCodeThread error");
	return code!=STILL_ACTIVE;
}

int ThreadImpl::getId()const
{
	return GetThreadId(handle_.impl());
}

bool sd::tools::thread::impl::multi_join( thread::iterator first, thread::iterator second, bool wait_all, int msec_time )
{
	int count = second - first;

	HANDLE* buf=new HANDLE[count];

	for( int i=0; first != second; ++first, ++i )
		buf[i] = (*first)->getHandle().impl();
		
	HRESULT result = WaitForMultipleObjects( count, &buf[0], wait_all, msec_time?msec_time:INFINITE  );

	delete buf;

	return result!=WAIT_TIMEOUT;
}


ThreadImpl* sd::tools::thread::impl::createThisThread()
{
	return new ThreadImpl(HHANDLE(GetCurrentThread()));
}